package com.imyuanma.qingyun.fs.service.impl;

import com.imyuanma.qingyun.common.exception.Exceptions;
import com.imyuanma.qingyun.common.util.AssertUtil;
import com.imyuanma.qingyun.common.util.StringUtil;
import com.imyuanma.qingyun.fs.configuration.FsBaseConfiguration;
import com.imyuanma.qingyun.fs.model.FsFile;
import com.imyuanma.qingyun.fs.model.enums.EFsMediaType;
import com.imyuanma.qingyun.fs.service.IFsFileService;
import com.imyuanma.qingyun.fs.service.IFsFileStreamService;
import com.imyuanma.qingyun.fs.util.FsBusinessUtil;
import com.imyuanma.qingyun.fs.util.ImageUtil;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * 文件流服务
 *
 * @author wangjy
 * @date 2022/07/24 00:19:42
 */
@Service
public class FsFileStreamServiceImpl implements IFsFileStreamService {

    private static final Logger logger = LoggerFactory.getLogger(FsFileStreamServiceImpl.class);

    @Autowired
    private FsBaseConfiguration fsBaseConfiguration;

    @Autowired
    private IFsFileService fsFileService;

    @PostConstruct
    public void init() {
        logger.info("[文件服务初始化] 初始化开始!");
        // 判断根目录是否有效,无效则创建对应目录
        File file = new File(fsBaseConfiguration.getRootDir());
        if (file.exists()) {
            if (file.isDirectory()) {
                logger.info("[文件服务初始化] 存在根目录:{}", fsBaseConfiguration.getRootDir());
            } else {
                throw Exceptions.baseException(String.format("文件服务初始化失败:配置的文件存储根目录[%s]为文件类型,无法初始化文件夹!", fsBaseConfiguration.getRootDir()));
            }
        } else {
            // 不存在,则创建
            file.mkdirs();
            logger.info("[文件服务初始化] 成功创建文件服务根目录:{}", fsBaseConfiguration.getRootDir());
        }

//        INSERT INTO tb_fs_file(id, NAME, save_name, STATUS, remark, media_type, folder_id, file_type, addr, path, create_user_id, update_user_id)
//        VALUES ('root', 'root', 'root', 'NORMAL', '根目录', 'FOLDER', '0', 'FOLDER', '/fs', '/fs_static', 1, 1)
        // 初始化虚拟root根文件夹
        FsFile fsRoot = fsFileService.getRoot();
        if (fsRoot == null) {
            throw Exceptions.baseException("文件服务初始化失败:root根节点查询失败,请检查文件数据表[tb_fs_file]的根节点[root]是否存在!");
        }
        if (StringUtil.isNotBlank(fsRoot.getAddr())) {
            File root = new File(fsBaseConfiguration.getRootDir() + fsRoot.getAddr());
            if (!root.exists()) {
                root.mkdirs();
                logger.info("[文件服务初始化] 成功创建文件服务root虚拟根节点磁盘目录:{}", (fsBaseConfiguration.getRootDir() + fsRoot.getAddr()));
            }
        }
        logger.info("[文件服务初始化] 初始化完成!");
    }

    /**
     * 保存文件,默认存放到根目录
     *
     * @param file         文件信息
     * @param businessCode 业务编号,可以为空
     * @return
     */
    @Override
    public FsFile saveFile(MultipartFile file, String businessCode) {
        return this.saveFile(file, fsFileService.getRoot(), businessCode);
    }

    /**
     * 上传文件到指定文件夹
     *
     * @param file         文件信息
     * @param folderId     文件夹id
     * @param businessCode 业务编号,可以为空
     * @return
     */
    @Override
    public FsFile saveFile(MultipartFile file, String folderId, String businessCode) {
        FsFile folder = StringUtil.isNotBlank(folderId) ? fsFileService.get(folderId) : fsFileService.getRoot();
        if (folder == null) {
            throw Exceptions.paramException(String.format("文件夹[%s]不存在", folderId));
        }
        return this.saveFile(file, folder, businessCode);
    }

    /**
     * 上传文件到指定文件夹
     *
     * @param file         文件信息
     * @param folder       文件夹
     * @param businessCode 业务编号,可以为空
     * @return
     */
    @Override
    public FsFile saveFile(MultipartFile file, FsFile folder, String businessCode) {
        AssertUtil.notNull(file, "待上传文件无效");
        AssertUtil.notNull(folder, "文件夹不存在");
        AssertUtil.notBlank(folder.getAddr(), "文件夹物理地址无效");
        AssertUtil.notBlank(folder.getPath(), "文件夹访问路径无效");
        if (file.isEmpty()) {
            throw Exceptions.paramException("待上传文件无效");
        }

        // 文件元信息
        FsFile fsFile = FsBusinessUtil.buildFsFile(file, folder, businessCode);
        logger.info("[保存文件] 待保存文件元信息={}", fsFile);

        // 磁盘文件
        File saveFile = new File(fsBaseConfiguration.getRootDir() + fsFile.getAddr());

        // 创建磁盘目录
        File dirFile = saveFile.getParentFile();
        if (!dirFile.exists()) {
            dirFile.mkdirs();
            logger.info("[保存文件] 创建文件目录:{}", dirFile.getAbsolutePath());
        }

        // 写入文件
        try {
            // 源文件
            file.transferTo(saveFile);
            if (EFsMediaType.IMG.getCode().equals(fsFile.getMediaType())) {
                // 如果是tif格式图片, 则转为png格式
                if (FsBusinessUtil.isTif(fsFile.getName())) {
                    // 元数据更新为png格式
                    FsBusinessUtil.rewriteTifFsFile(fsFile, "png");
                    // 格式转为png
                    saveFile = ImageUtil.tifToPng(saveFile, fsBaseConfiguration.getRootDir() + fsFile.getAddr());
                }
                // 生成缩略图
                if (fsFile.getImageWidth() != null && fsFile.getImageHeight() != null) {
                    // 裁剪缩略图
                    int width = Math.min(fsFile.getImageWidth(), 265);
                    int height = Math.min(fsFile.getImageHeight(), 155);
                    ImageUtil.cutImage(saveFile, width, height, 0, 0);
                }
            }
        } catch (IOException e) {
            logger.error("[保存文件] 写磁盘文件时异常,写入地址={}", saveFile.getAbsolutePath(), e);
            throw Exceptions.baseException("保存文件失败");
        }

        // 元信息落库
        fsFileService.insertSelective(fsFile);

        return fsFile;
    }



    /**
     * 批量上传文件到指定文件夹
     *
     * @param files
     * @param folderId
     * @param businessCode 业务编号,可以为空
     * @return
     */
    @Override
    public List<FsFile> saveFiles(List<MultipartFile> files, String folderId, String businessCode) {
        FsFile folder = StringUtil.isNotBlank(folderId) ? fsFileService.get(folderId) : fsFileService.getRoot();
        if (folder == null) {
            throw Exceptions.paramException(String.format("文件夹[%s]不存在", folderId));
        }
        List<FsFile> list = new ArrayList<>();
        for (MultipartFile file : files) {
            list.add(this.saveFile(file, folder, businessCode));
        }
        return list;
    }

    /**
     * 删除文件
     *
     * @param fileId 文件编号
     * @return
     */
    @Override
    public boolean dropFile(String fileId) {
        FsFile fileInfo = fsFileService.get(fileId);
        if (fileInfo != null) {
            if (StringUtil.isNotBlank(fileInfo.getAddr())) {
                File file = new File(fsBaseConfiguration.getRootDir() + fileInfo.getAddr());
                if (file.exists()) {
                    if (file.isDirectory()) {
                        logger.info("[文件删除] 删除失败:暂不支持文件夹删除操作!");
                        return false;
                    } else {
                        // 删除文件
                        file.delete();
                        logger.info("[文件删除] 成功删除文件:{}", file.getAbsolutePath());
                    }
                } else {
                    logger.info("[文件删除] 文件实体不存在!");
                }
                // 删除文件元信息
                fsFileService.delete(fileId);
            } else {
                logger.info("[文件删除] 删除失败:文件地址信息无效:{}", fileInfo.getAddr());
                return false;
            }
        }
        return true;
    }

    /**
     * 删除文件夹
     *
     * @param folderId 文件夹编号
     * @return
     */
    @Override
    public boolean dropFolder(String folderId) {
        //查询文件夹信息
        FsFile folder = fsFileService.get(folderId);
        if (folder != null) {
            if (StringUtil.isNotBlank(folder.getAddr())) {
                //删除整个文件夹
                File file = new File(fsBaseConfiguration.getRootDir() + folder.getAddr());
                try {
                    FileUtils.deleteDirectory(file);
                } catch (IOException e) {
                    logger.error("[删除文件夹] 删除文件夹出错,文件夹={}", fsBaseConfiguration.getRootDir() + folder.getAddr(), e);
                    throw Exceptions.baseException("删除文件夹出错");
                }
                logger.info("[文件夹删除] 删除的文件夹路径为:{}", fsBaseConfiguration.getRootDir() + folder.getAddr());
                // 删除文件夹下的文件信息
                fsFileService.deleteAllByFolder(folderId);
                // 删除文件夹信息
                fsFileService.delete(folderId);
            } else {
                logger.info("[文件夹删除] 删除失败:文件夹地址信息无效:{}", folder.getAddr());
                return false;
            }
        }
        return true;
    }

    /**
     * 创建文件夹
     *
     * @param folder 文件夹信息
     * @return 文件夹信息
     */
    @Override
    public FsFile createFolder(FsFile folder) {
        return null;
    }
}
